#include "xthread-waitqueue.h"
#include "inneral/xthread.h"
#include <assert.h>

void xthread_wait_queue_add(xthread_wait_queue_t *wait_queue, void *arg)
{
    xthread_struct_t *thread = (xthread_struct_t *) arg;
    xthread_spin_lock(&wait_queue->lock);
	assert(!list_find(&thread->list, &wait_queue->wait_list));
	list_add_tail(&thread->list, &wait_queue->wait_list);
    xthread_spin_unlock(&wait_queue->lock);
}

void xthread_wait_queue_sleep(xthread_wait_queue_t *wait_queue)
{
    xthread_struct_t *cur = (xthread_struct_t *) xthread_current;
    xthread_wait_queue_add(wait_queue, cur);
    xthread_block(XTHREAD_BLOCK);
}

void xthread_wait_queue_remove(xthread_wait_queue_t *wait_queue, void *thread_ptr)
{
    xthread_struct_t *thread = (xthread_struct_t *) thread_ptr;
    xthread_spin_lock(&wait_queue->lock);
	xthread_struct_t *target, *next;
	list_for_each_owner_safe (target, next, &wait_queue->wait_list, list) {
		if (target == thread) {
			list_del_init(&target->list);
			break;
		}
	}
    xthread_spin_unlock(&wait_queue->lock);
}

void xthread_wait_queue_wakeup(xthread_wait_queue_t *wait_queue)
{
    xthread_spin_lock(&wait_queue->lock);
	if (!list_empty(&wait_queue->wait_list)) {
        xthread_struct_t *thread = list_first_owner_or_null(&wait_queue->wait_list, xthread_struct_t, list);
		if (thread) {
            list_del(&thread->list);
            xthread_unblock(thread);
        }
    }
    xthread_spin_unlock(&wait_queue->lock);
}

void xthread_wait_queue_wakeup_all(xthread_wait_queue_t *wait_queue)
{
    xthread_spin_lock(&wait_queue->lock);
    xthread_struct_t *thread, *next;
    list_for_each_owner_safe (thread, next, &wait_queue->wait_list, list) {
		list_del(&thread->list);
        xthread_unblock(thread);
    }
    xthread_spin_unlock(&wait_queue->lock);
}
